#include "Camera.hpp"
#include "GLFW/glfw3.h"
#include "Window.hpp"


Camera::Camera(GLFWwindow* window, const flecs::world& ecs, const vec3& position, const glm::vec3& direction, float speed, float fov, float sensity) : Object3D(ecs, ecs.lookup("invisible")), window(window), direction(direction)
{
	this->speed = speed;
	sens = sensity;

	setDirection();
	teleport(position);

	proj_matrix = glm::perspective(R(fov), 4.0f / 3.0f, 0.1f, 1000.0f);
	getEntity().set<mat4>(proj_matrix * glm::lookAt(getPosition(), getPosition() + direction, globalUp));
	
	lastx = lasty = 0;
}
void Camera::rotate_callback(float x, float y)
{
	if (firstCursorAppear)
	{
		lastx = x, lasty = y;
		firstCursorAppear = false;
	}

	yaw += (x - lastx) * sens / 10;
	pitch += (lasty - y) * sens / 10;

	lastx = x;
	lasty = y;

	const float look_border = glm::radians(89.0f);
	pitch >  look_border ? pitch =  look_border : true;
	pitch < -look_border ? pitch = -look_border : true;

	const float cos_pitch = cosf(pitch);

	direction = glm::vec3
	(
		cosf(yaw) * cos_pitch,
		sinf(pitch),
		sinf(yaw) * cos_pitch
	);
	setDirection();
}
void Camera::process(float delta)
{
	glm::vec3 velocity(0.f);

	if (glfwGetKey(window, GLFW_KEY_W))
		velocity += direction;
	else if (glfwGetKey(window, GLFW_KEY_S))
		velocity -= direction;

	if (glfwGetKey(window, GLFW_KEY_A))
		velocity -= glm::normalize(glm::cross(direction, globalUp));
	else if (glfwGetKey(window, GLFW_KEY_D))
		velocity += glm::normalize(glm::cross(direction, globalUp));

	velocity *= speed * delta;

	if (glfwGetKey(window, GLFW_KEY_SPACE))
		velocity.y += speed * delta;
	else if (glfwGetKey(window, GLFW_KEY_C))
		velocity.y -= speed * delta;

  if (glfwGetKey(window, GLFW_KEY_ESCAPE))
	{
		glfwDestroyWindow(window);
		glfwTerminate();
		exit(0);
	}
  else if (glfwGetKey(window, GLFW_KEY_ENTER))
  {
    if (!firstCursorAppear)
    {
      glfwSetCursorPosCallback(window, 0);
      glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
      firstCursorAppear = true;
    }
    else
    {
      glfwSetCursorPosCallback(window, mouse_callback);
      glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    }
  }

	move(velocity);
	getEntity().set<mat4>(proj_matrix * glm::lookAt(getPosition(), getPosition() + direction, globalUp));
}
void Camera::lookAt(const vec3& target)
{
	direction = target;
	getEntity().set<mat4>(proj_matrix * glm::lookAt(getPosition(), getPosition() + direction, globalUp));
	getEntity().set<quat, tagRotation>(glm::quat(glm::normalize(direction), globalUp));
}
